{% extends "base.html" %}

{% block head %}
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/element-plus"></script>
<script src="https://unpkg.com/@element-plus/icons-vue"></script>
<style>
    .file-select { margin-bottom: 20px; }
    .pagination { margin-top: 20px; text-align: right; }
    .chunk-content {
        max-width: 900px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .chunk-content.full {
        max-width: 100%;
        overflow: visible;
        text-overflow: initial;
        white-space: pre-wrap;
    }
    .btn {
        padding: 6px 16px;
        border: none;
        border-radius: 4px;
        background: #409EFF;
        color: #fff;
        cursor: pointer;
        margin-right: 8px;
        font-size: 14px;
        transition: background 0.2s;
    }
    .btn:hover { background: #337ecc; }
    .btn-danger { background: #e74c3c; }
    .btn-danger:hover { background: #c0392b; }
    .error-tip { color: #e74c3c; margin: 20px 0; text-align: center; }
    .loading-tip { color: #409EFF; margin: 20px 0; text-align: center; }
    .star-rating {
        display: flex;
        align-items: center;
        margin-top: 4px;
    }
    .star {
        font-size: 20px;
        color: #FFD700 !important; /* 高亮金色 */
        cursor: pointer;
        margin-right: 2px;
        transition: color 0.2s;
        text-shadow: 0 0 4px #222, 0 0 2px #fff;
    }
    .star.inactive {
        color: #444 !important; /* 深灰色，深色主题下对比明显 */
        opacity: 0.5;
        text-shadow: none;
    }
    .star-rating .score-label {
        margin-left: 8px;
        color: #888;
        font-size: 13px;
    }
    .btn-model-score {
        background: #67C23A;
        color: #fff;
        margin-right: 8px;
    }
    .btn-model-score:hover {
        background: #529b2e;
    }
</style>
{% endblock %}

{% block content %}
<script>
window._t = {{ t|tojson }};
window._lang = "{{ lang }}";
</script>
{% raw %}
<div id="app">
    <h2 v-text="t['chunk_manage']"></h2>
    <div v-if="error" class="error-tip">{{ error }}</div>
    <div v-else>
        <div v-if="loading" class="loading-tip">{{ t['loading'] }}</div>
        <div v-else>
            <div style="margin: 16px 0;display:flex;align-items:center;">
                <span style="margin-right:8px;">{{ t['generate_qa_count'] }}</span>
                <input v-model="qaNum" type="number" min="1" max="20" :placeholder="t['generate_qa_count']" style="width:160px; margin-right:12px;" />
                <button class="btn" @click="generateQA" :disabled="selectedChunks.length===0 || !qaNum || generating">{{ t['model_generate'] || '模型生成' }}</button>
                <button class="btn btn-model-score" @click="batchModelScore" :disabled="!selectedChunks.length">{{ t['model_score'] || '模型评分' }}</button>
                <button class="btn" @click="batchDelete" :disabled="!selectedChunks.length">{{ t['batch_delete'] }}</button>
                <el-progress v-if="generating" :percentage="progress" style="width:200px;display:inline-block;margin-left:16px;vertical-align:middle;" :stroke-width="16" status="active"></el-progress>
                <el-progress v-if="scoring" :percentage="scoreProgress" style="width:200px;display:inline-block;margin-left:16px;vertical-align:middle;" :stroke-width="16" status="active"></el-progress>
            </div>
            <div class="file-select">
                <el-select v-model="selectedFileId" :placeholder="t['select_file']" @change="fetchChunks">
                    <el-option
                        v-for="file in files"
                        :key="file.id"
                        :label="file.file_name"
                        :value="file.id">
                    </el-option>
                </el-select>
            </div>
            <el-table v-if="chunks.length > 0" :data="chunks" style="width: 100%" @selection-change="handleSelectionChange" ref="chunkTable">
                <el-table-column type="selection" width="48"></el-table-column>
                <el-table-column :label="t['chunk_content']" width="900">
                    <template v-slot="scope">
                        <div style="display:flex;align-items:center;">
                            <span style="color:#409EFF;margin-right:8px;">[{{ scope.row.qa_count || 0 }}]</span>
                            <div class="chunk-content" :class="{full: scope.row.showQA}" :title="scope.row.full_content" style="flex:1;cursor:pointer;" @click="toggleQA(scope.row)">
                                {{ scope.row.showQA ? scope.row.full_content : scope.row.content }}
                            </div>
                        </div>
                        <div v-if="scope.row.showQA" class="qa-theme" style="background:#f7f8fa;padding:12px 18px 8px 18px;margin-top:8px;border-radius:6px;">
                            <div v-if="scope.row.qaLoading" style="color:#888;">{{ t['loading'] }}</div>
                            <div v-else-if="scope.row.qaList && scope.row.qaList.length">
                                <div v-for="(qa, idx) in scope.row.qaList" :key="idx" style="margin-bottom:10px;">
                                    <div style="font-weight:bold;display:flex;align-items:center;">
                                        <el-icon style="cursor:pointer;color:#e74c3c;margin-right:6px;" @click="deleteQA(scope.row, qa, idx)"><Delete /></el-icon>
                                        <span v-if="!qa.editingQ" @click="editQ(qa)">Q: {{ qa.question }}</span>
                                        <input v-else v-model="qa.editQ" @blur="saveQ(scope.row, qa, idx)" @keyup.enter="saveQ(scope.row, qa, idx)" style="flex:1;margin-right:8px;" />
                                    </div>
                                    <div style="margin-left:18px;">
                                        <span v-if="!qa.editingA" @click="editA(qa)">A: {{ qa.answer }}</span>
                                        <input v-else v-model="qa.editA" @blur="saveA(scope.row, qa, idx)" @keyup.enter="saveA(scope.row, qa, idx)" style="width:90%;" />
                                    </div>
                                    <!-- 评分控件 -->
                                    <div class="star-rating">
                                        <span v-for="star in 5" :key="star" class="star" :class="{inactive: !qa.score || star > qa.score}" @click="setQAScore(qa, star)">
                                            ★
                                        </span>
                                        <span class="score-label" v-if="qa.score">{{ qa.score }}/5</span>
                                        <span class="score-label" v-else>{{ t['no_score'] || '未评分' }}</span>
                                    </div>
                                </div>
                            </div>
                            <div v-else style="color:#888;">{{ t['no_qa_pairs'] }}</div>
                        </div>
                    </template>
                </el-table-column>
                <el-table-column :label="t['operation']" width="100">
                    <template v-slot="scope">
                        <el-button type="danger" size="small" @click="handleDelete(scope.row.id)">{{ t['delete'] }}</el-button>
                    </template>
                </el-table-column>
            </el-table>

            <div v-else-if="selectedFileId" class="no-data">
                该文件暂无分块数据
            </div>

            <div v-else class="no-data">
                请选择文件查看分块数据
            </div>

            <div class="pagination" v-if="chunks.length > 0">
                <el-pagination
                    v-model:current-page="currentPage"
                    v-model:page-size="pageSize"
                    :page-sizes="[10, 20, 50, 100]"
                    layout="total, sizes, prev, pager, next"
                    :total="total"
                    @size-change="handleSizeChange"
                    @current-change="handleCurrentChange">
                </el-pagination>
            </div>
        </div>
    </div>
</div>

<script>
const { createApp, ref, onMounted } = Vue
const { Delete } = ElementPlusIconsVue

createApp({
    setup() {
        const t = window._t;
        const files = ref([])
        const chunks = ref([])
        const selectedFileId = ref('')
        const currentPage = ref(1)
        const pageSize = ref(10)
        const total = ref(0)
        const qaNum = ref(3)
        const selectedChunks = ref([])
        const chunkTable = ref(null)
        const generating = ref(false)
        const progress = ref(0)
        const loading = ref(true)
        const error = ref("")
        const scoring = ref(false)
        const scoreProgress = ref(0)

        const truncate = (text, len = 350) => {
            if (!text) return '';
            return text.length > len ? text.slice(0, len) + '...' : text;
        }

        const fetchFiles = async () => {
            loading.value = true;
            error.value = "";
            try {
                const response = await fetch('/api/files')
                if (!response.ok) throw new Error(t['fetch_files_fail'] || 'Failed to fetch files');
                const data = await response.json()
                files.value = data.files
                if (files.value.length > 0 && !selectedFileId.value) {
                    selectedFileId.value = files.value[0].id
                    await fetchChunks()
                }
            } catch (err) {
                error.value = t['fetch_files_fail'] || (err.message || '加载文件失败');
            } finally {
                loading.value = false;
            }
        }

        const fetchChunks = async () => {
            if (!selectedFileId.value) return
            loading.value = true;
            error.value = "";
            try {
                const response = await fetch(`/api/files/${selectedFileId.value}/chunks?page=${currentPage.value}&page_size=${pageSize.value}`)
                if (!response.ok) throw new Error(t['fetch_chunks_fail'] || 'Failed to fetch chunks');
                const data = await response.json()
                for (const chunk of data.chunks) {
                    try {
                        const qaResp = await fetch(`/api/chunks/${chunk.id}/qa`)
                        const qaData = await qaResp.json()
                        chunk.qa_count = qaData.count || 0
                    } catch (e) {
                        chunk.qa_count = 0
                    }
                }
                chunks.value = data.chunks
                total.value = data.total
            } catch (err) {
                error.value = t['fetch_chunks_fail'] || (err.message || '加载分块失败');
            } finally {
                loading.value = false;
            }
        }

        const handleSizeChange = (val) => {
            pageSize.value = val
            fetchChunks()
        }

        const handleCurrentChange = (val) => {
            currentPage.value = val
            fetchChunks()
        }

        const handleDelete = (chunkId) => {
            ElementPlus.ElMessageBox.confirm(
                t['delete_chunk_confirm'],
                t['alert_title'],
                {
                    confirmButtonText: t['confirm'],
                    cancelButtonText: t['cancel'],
                    type: 'warning',
                    center: true
                }
            ).then(async () => {
                try {
                    const resp = await fetch(`/api/chunks/${chunkId}`, {
                        method: 'DELETE',
                        headers: { 'Accept': 'application/json' }
                    });
                    const data = await resp.json();
                    if (data.status === 'success') {
                        ElementPlus.ElMessage.success(t['delete_chunk_success']);
                        fetchChunks();
                    } else {
                        ElementPlus.ElMessage.error(data.message || t['delete_chunk_fail']);
                    }
                } catch (e) {
                    ElementPlus.ElMessage.error(t['delete_chunk_fail']);
                }
            }).catch(() => {
                // 用户取消，无需处理
            });
        };

        const handleSelectionChange = (val) => { selectedChunks.value = val }

        const generateQA = async () => {
            if (!selectedChunks.value.length || !qaNum.value) return
            generating.value = true
            progress.value = 0
            const lang = window._lang;
            // 模拟进度条（实际可用后端分步返回进度）
            const timer = setInterval(() => {
                if (progress.value < 90) progress.value += 5
            }, 300)
            const segments = selectedChunks.value.map(c => ({ id: c.id, content: c.content }))
            const resp = await fetch('/api/generate-qa', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ segments, num_pairs: qaNum.value, file_id: selectedFileId.value, lang })
            })
            const data = await resp.json()
            clearInterval(timer)
            progress.value = 100
            generating.value = false
            if (data.status === 'success') {
                ElementPlus.ElMessageBox.alert(
                    t['generate_qa_success_msg'].replace('{count}', data.count || 0),
                    t['generate_qa_success_title'],
                    {type:'success'}
                ).then(() => { window.location.reload(); });
            } else {
                ElementPlus.ElMessageBox.alert(
                    data.message || t['generate_qa_fail_msg'],
                    t['generate_qa_fail_title'],
                    {type:'error'}
                )
            }
        }

        const toggleQA = async (row) => {
            if (row.showQA) {
                row.showQA = false;
                return;
            }
            if (!row.qaList) {
                row.qaLoading = true;
                try {
                    const resp = await fetch(`/api/chunks/${row.id}/qa`);
                    const data = await resp.json();
                    if (data.status === 'success') {
                        row.qaList = data.data;
                    } else {
                        row.qaList = [];
                    }
                } catch (e) {
                    row.qaList = [];
                }
                row.qaLoading = false;
            }
            row.showQA = true;
        }

        // 新增：Q/A点击可编辑
        const editQ = (qa) => {
            qa.editingQ = true;
            qa.editQ = qa.question;
        }
        const saveQ = async (row, qa, idx) => {
            qa.editingQ = false;
            // 调用后端保存接口
            try {
                const resp = await fetch(`/api/qa/${qa.id}/update`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ question: qa.editQ, answer: qa.answer })
                });
                const data = await resp.json();
                if (data.status === 'success') {
                    qa.question = qa.editQ;
                } else {
                    ElementPlus.ElMessage.error('保存失败');
                }
            } catch (e) {
                ElementPlus.ElMessage.error('保存失败');
            }
        }
        const editA = (qa) => {
            qa.editingA = true;
            qa.editA = qa.answer;
        }
        const saveA = async (row, qa, idx) => {
            qa.editingA = false;
            // 调用后端保存接口
            try {
                const resp = await fetch(`/api/qa/${qa.id}/update`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ question: qa.question, answer: qa.editA })
                });
                const data = await resp.json();
                if (data.status === 'success') {
                    qa.answer = qa.editA;
                } else {
                    ElementPlus.ElMessage.error('保存失败');
                }
            } catch (e) {
                ElementPlus.ElMessage.error('保存失败');
            }
        }
        const deleteQA = async (row, qa, idx) => {
            ElementPlus.ElMessageBox.confirm(
                t['delete_qa_confirm'],
                t['alert_title'],
                {
                    confirmButtonText: t['confirm'],
                    cancelButtonText: t['cancel'],
                    type: 'warning',
                    center: true
                }
            ).then(async () => {
                try {
                    const resp = await fetch(`/api/qa/${qa.id}/delete`, { method: 'POST' });
                    const data = await resp.json();
                    if (data.status === 'success') {
                        row.qaList.splice(idx, 1);
                        ElementPlus.ElMessage.success(t['delete_success']);
                    } else {
                        ElementPlus.ElMessage.error(t['delete_fail']);
                    }
                } catch (e) {
                    ElementPlus.ElMessage.error(t['delete_fail']);
                }
            }).catch(() => {});
        }

        const batchDelete = async () => {
            if (!selectedChunks.value.length) return;
            ElementPlus.ElMessageBox.confirm(
                t['delete_selected_confirm'],
                t['alert_title'],
                {
                    confirmButtonText: t['confirm'],
                    cancelButtonText: t['cancel'],
                    type: 'warning',
                    center: true
                }
            ).then(async () => {
                try {
                    const ids = selectedChunks.value.map(c => c.id);
                    const resp = await fetch('/api/chunks_delete', {
                        method: 'POST',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify({ids})
                    });
                    if (resp.ok) {
                        ElementPlus.ElMessage.success(t['delete_selected_success']);
                        fetchChunks();
                    } else {
                        ElementPlus.ElMessage.error(t['delete_selected_fail']);
                    }
                } catch (err) {
                    ElementPlus.ElMessage.error(t['delete_selected_fail']);
                }
            }).catch(() => {});
        };

        // 评分相关逻辑
        const setQAScore = async (qa, score) => {
            try {
                const resp = await fetch(`/api/qa-pairs/${qa.id}/score`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ score })
                });
                const data = await resp.json();
                if (data.status === 'success') {
                    qa.score = score;
                    ElementPlus.ElMessage.success(t['save_success']);
                } else {
                    ElementPlus.ElMessage.error(data.message || t['save_fail']);
                }
            } catch (e) {
                ElementPlus.ElMessage.error(t['save_fail']);
            }
        };
        // 批量模型评分
        const batchModelScore = async () => {
            if (!selectedChunks.value.length) return;
            // 收集所有分块下的问答对ID
            let qaIds = [];
            for (const chunk of selectedChunks.value) {
                if (chunk.qaList && chunk.qaList.length) {
                    qaIds.push(...chunk.qaList.map(q => q.id));
                } else {
                    // 若未加载，需请求
                    try {
                        const resp = await fetch(`/api/chunks/${chunk.id}/qa`);
                        const data = await resp.json();
                        if (data.status === 'success') {
                            qaIds.push(...data.data.map(q => q.id));
                        }
                    } catch (e) {}
                }
            }
            if (!qaIds.length) {
                ElementPlus.ElMessage.warning(t['no_qa_pairs'] || '无问答对可评分');
                return;
            }
            scoring.value = true;
            scoreProgress.value = 0;
            // 模拟进度条
            const timer = setInterval(() => {
                if (scoreProgress.value < 90) scoreProgress.value += 5;
            }, 300);
            ElementPlus.ElMessage.info(t['testing'] || '正在评分...');
            try {
                const resp = await fetch('/api/qa-pairs/auto-score', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ qa_ids: qaIds })
                });
                const data = await resp.json();
                clearInterval(timer);
                scoreProgress.value = 100;
                scoring.value = false;
                if (data.status === 'success') {
                    ElementPlus.ElMessage.success(t['save_success']);
                    // 刷新分数
                    for (const chunk of selectedChunks.value) {
                        if (chunk.qaList && chunk.qaList.length) {
                            for (const qa of chunk.qaList) {
                                const found = data.results.find(r => r.qa_id === qa.id);
                                if (found && found.score) qa.score = found.score;
                            }
                        }
                    }
                } else {
                    ElementPlus.ElMessage.error(data.message || t['save_fail']);
                }
            } catch (e) {
                clearInterval(timer);
                scoring.value = false;
                ElementPlus.ElMessage.error(t['save_fail']);
            }
        };

        onMounted(() => {
            fetchFiles()
        })

        return {
            t,
            files,
            chunks,
            selectedFileId,
            currentPage,
            pageSize,
            total,
            fetchChunks,
            handleSizeChange,
            handleCurrentChange,
            handleDelete,
            qaNum,
            selectedChunks,
            chunkTable,
            handleSelectionChange,
            generateQA,
            generating,
            progress,
            truncate,
            toggleQA,
            editQ,
            saveQ,
            editA,
            saveA,
            deleteQA,
            batchDelete,
            loading,
            error,
            setQAScore,
            batchModelScore,
            scoring,
            scoreProgress
        }
    }
}).use(ElementPlus)
.component('Delete', Delete)
.mount('#app')
</script>
{% endraw %}
{% endblock %} 